package singlestat

import (
	
	

	
	
	
	
	
	
	
)

// Option represents an option that can be used to configure a single stat panel.
type Option func(stat *SingleStat) error

// StatType let you set the function that your entire query is reduced into a
// single value with.
type StatType string

const (
	// Min will return the smallest value in the series.
	Min StatType = "min"

	// Max will return the largest value in the series.
	Max StatType = "max"

	// Avg will return the average of all the non-null values in the series.
	Avg StatType = "avg"

	// Current will return the last value in the series. If the series ends on
	// null the previous value will be used.
	Current StatType = "current"

	// Total will return the sum of all the non-null values in the series.
	Total StatType = "total"

	// First will return the first value in the series.
	First StatType = "first"

	// Delta will return the total incremental increase (of a counter) in the
	// series. An attempt is made to account for counter resets, but this will
	// only be accurate for single instance metrics. Used to show total
	// counter increase in time series.
	Delta StatType = "delta"

	// Diff will return difference between ‘current’ (last value) and ‘first’..
	Diff StatType = "diff"

	// Range will return the difference between ‘min’ and ‘max’. Useful to
	// show the range of change for a gauge..
	Range StatType = "range"

	// Name will return the name value in the series.
	Name StatType = "name"
)

// ValueMap allows to map a value into explicit text.
type ValueMap struct {
	Value string
	Text  string
}

// RangeMap allows to map a range of values into explicit text.
type RangeMap struct {
	From string
	To   string
	Text string
}

// nolint: gochecknoglobals
var valueToTextMapping = 1

// nolint: gochecknoglobals
var rangeToTextMapping = 2

// SingleStat represents a single stat panel.
type SingleStat struct {
	Builder *sdk.Panel
}

// New creates a new single stat panel.
func ( string,  ...Option) (*SingleStat, error) {
	 := &SingleStat{Builder: sdk.NewSinglestat()}

	 := "value to text"
	 := "range to text"

	.Builder.IsNew = false
	 := uint(valueToTextMapping)
	.Builder.SinglestatPanel.MappingType = &
	.Builder.SinglestatPanel.MappingTypes = []*sdk.MapType{
		{
			Name:  &,
			Value: &valueToTextMapping,
		},
		{
			Name:  &,
			Value: &rangeToTextMapping,
		},
	}
	.Builder.SinglestatPanel.SparkLine = sdk.SparkLine{}

	for ,  := range append(defaults(), ...) {
		if  := ();  != nil {
			return nil, 
		}
	}

	return , nil
}

func defaults() []Option {
	return []Option{
		Span(6),
		ValueFontSize("100%"),
		ValueType(Avg),
		Colors([3]string{"#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"}),
		ValuesToText([]ValueMap{
			{
				Value: "null",
				Text:  "N/A",
			},
		}),
		SparkLineColor("rgb(31, 120, 193)"),
		SparkLineFillColor("rgba(31, 118, 189, 0.18)"),
	}
}

// Links adds links to be displayed on this panel.
func ( ...links.Link) Option {
	return func( *SingleStat) error {
		.Builder.Links = make([]sdk.Link, 0, len())

		for ,  := range  {
			.Builder.Links = append(.Builder.Links, .Builder)
		}

		return nil
	}
}

// DataSource sets the data source to be used by the panel.
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.Datasource = &sdk.DatasourceRef{LegacyName: }

		return nil
	}
}

// WithPrometheusTarget adds a prometheus query to the graph.
func ( string,  ...prometheus.Option) Option {
	 := prometheus.New(, ...)

	return func( *SingleStat) error {
		.Builder.AddTarget(&sdk.Target{
			RefID:          .Ref,
			Hide:           .Hidden,
			Expr:           .Expr,
			IntervalFactor: .IntervalFactor,
			Interval:       .Interval,
			Step:           .Step,
			LegendFormat:   .LegendFormat,
			Instant:        .Instant,
			Format:         .Format,
		})

		return nil
	}
}

// WithGraphiteTarget adds a Graphite target to the graph.
func ( string,  ...graphite.Option) Option {
	 := graphite.New(, ...)

	return func( *SingleStat) error {
		.Builder.AddTarget(.Builder)

		return nil
	}
}

// WithInfluxDBTarget adds an InfluxDB target to the graph.
func ( string,  ...influxdb.Option) Option {
	 := influxdb.New(, ...)

	return func( *SingleStat) error {
		.Builder.AddTarget(.Builder)

		return nil
	}
}

// WithStackdriverTarget adds a stackdriver query to the graph.
func ( *stackdriver.Stackdriver) Option {
	return func( *SingleStat) error {
		.Builder.AddTarget(.Builder)

		return nil
	}
}

// Span sets the width of the panel, in grid units. Should be a positive
// number between 1 and 12. Example: 6.
func ( float32) Option {
	return func( *SingleStat) error {
		if  < 1 ||  > 12 {
			return fmt.Errorf("span must be between 1 and 12: %w", errors.ErrInvalidArgument)
		}

		.Builder.Span = 

		return nil
	}
}

// Height sets the height of the panel, in pixels. Example: "400px".
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.Height = &

		return nil
	}
}

// Description annotates the current visualization with a human-readable description.
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.Description = &

		return nil
	}
}

// Transparent makes the background transparent.
func () Option {
	return func( *SingleStat) error {
		.Builder.Transparent = true

		return nil
	}
}

// Unit sets the unit of the data displayed on this axis.
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.Format = 

		return nil
	}
}

// Decimals sets the number of decimals that should be displayed.
func ( int) Option {
	return func( *SingleStat) error {
		if  < 0 {
			return fmt.Errorf("decimals must be greater than 0: %w", errors.ErrInvalidArgument)
		}

		.Builder.SinglestatPanel.Decimals = 

		return nil
	}
}

// SparkLine displays the spark line summary of the series in addition to the
// single stat.
func () Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.SparkLine.Show = true
		.Builder.SinglestatPanel.SparkLine.Full = false

		return nil
	}
}

// FullSparkLine displays a full height spark line summary of the series in
// addition to the single stat.
func () Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.SparkLine.Show = true
		.Builder.SinglestatPanel.SparkLine.Full = true

		return nil
	}
}

// SparkLineColor sets the line color of the spark line.
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.SparkLine.LineColor = &

		return nil
	}
}

// SparkLineFillColor sets the color the spark line will be filled with.
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.SparkLine.FillColor = &

		return nil
	}
}

// SparkLineYMin defines the smallest value expected on the Y axis of the spark line.
func ( float64) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.SparkLine.YMin = &

		return nil
	}
}

// SparkLineYMax defines the largest value expected on the Y axis of the spark line.
func ( float64) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.SparkLine.YMax = &

		return nil
	}
}

// ValueType configures how the series will be reduced to a single value.
func ( StatType) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.ValueName = string()

		return nil
	}
}

// ValueFontSize sets the font size used to display the value (eg: "100%").
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.ValueFontSize = 

		return nil
	}
}

// Prefix sets the text used as prefix of the value.
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.Prefix = &

		return nil
	}
}

// PrefixFontSize sets the size used for the prefix text (eg: "110%").
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.PrefixFontSize = &

		return nil
	}
}

// Postfix sets the text used as postfix of the value.
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.Postfix = &

		return nil
	}
}

// PostfixFontSize sets the size used for the postfix text (eg: "110%")
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.PostfixFontSize = &

		return nil
	}
}

// ColorValue will show the threshold's colors on the value itself.
func () Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.ColorValue = true

		return nil
	}
}

// ColorBackground will show the threshold's colors in the background.
func () Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.ColorBackground = true

		return nil
	}
}

// Thresholds change the background and value colors dynamically within the
// panel, depending on the Singlestat value. The threshold is defined by 2
// values which represent 3 ranges that correspond to the three colors directly
// to the right.
func ( [2]string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.Thresholds = strings.Join([]string{[0], [1]}, ",")

		return nil
	}
}

// Colors define which colors will be applied to the single value based on the
// threshold levels.
func ( [3]string) Option {
	return func( *SingleStat) error {
		.Builder.SinglestatPanel.Colors = []string{[0], [1], [2]}

		return nil
	}
}

// ValuesToText allows to translate the value of the summary stat into explicit
// text.
func ( []ValueMap) Option {
	return func( *SingleStat) error {
		 := make([]sdk.ValueMap, 0, len())

		for ,  := range  {
			 = append(, sdk.ValueMap{
				Op:       "=",
				TextType: .Text,
				Value:    .Value,
			})
		}

		 := uint(valueToTextMapping)
		.Builder.SinglestatPanel.MappingType = &
		.Builder.SinglestatPanel.ValueMaps = 

		return nil
	}
}

// RangesToText allows to translate the value of the summary stat into explicit
// text.
func ( []RangeMap) Option {
	return func( *SingleStat) error {
		 := make([]*sdk.RangeMap, 0, len())

		for  := range  {
			 = append(, &sdk.RangeMap{
				From: &[].From,
				To:   &[].To,
				Text: &[].Text,
			})
		}

		 := uint(rangeToTextMapping)
		.Builder.SinglestatPanel.MappingType = &
		.Builder.SinglestatPanel.RangeMaps = 

		return nil
	}
}

// Repeat configures repeating a panel for a variable
func ( string) Option {
	return func( *SingleStat) error {
		.Builder.Repeat = &

		return nil
	}
}

// RepeatDirection configures repeating vertical or horizontal
func ( sdk.RepeatDirection) Option {
	return func( *SingleStat) error {
		.Builder.RepeatDirection = &

		return nil
	}
}